﻿using System;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

namespace CloudReader.Win32
{
    //摘要:
    //    鼠标钩子的封装，主要用于检测当前客户端机器的状态
    // 描述:
    //     该类使用Timer控件作为主体，每隔一秒检测一次Token值并且每一秒自增Token，如果Token一直<=2则说明机器处于操作状态
    //     则返回True事件，否则返回false

        // @ Author:罗应良
        // @ Date: 2017/2/13

    public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
    public class Win32MouseHook
    {

        #region P/Invoke
        //摘要
        //      P/Invoke 区域
        //用于调用钩子函数所声明的必要的API函数

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SetWindowsHookEx(int hookid, HookProc pfnHook, IntPtr hInst, int threadid);
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern IntPtr CallNextHookEx(IntPtr hhook, int code, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhook);
        [DllImport("kernel.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        public static extern int GetCurrentThreadId();
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        #endregion

        private const int WH_MSGFILTER = 7;
        //摘要
        // 声明一个安装钩子线程地址
        //
        private IntPtr _iHookHandle = IntPtr.Zero;

        //摘要
        // 声明一个HookHandle和非托管的钩子线程地址
        //
        private GCHandle _iHookProcHandle;
        private HookProc _iHookMethod;
        private const int WH_MOUSE_LL = 14;
        private const int WH_MOUSE_Move = 0x200;
        private System.Timers.Timer T = new System.Timers.Timer(1000);
        private int Token = 0;

        public Win32MouseHook()
        {
            T.Elapsed += (o, e) =>
            {
                Token++;
                MouseState?.Invoke(Token <= 2 ? true : false);
            };
        }

        //摘要
        //    用于捕获鼠标移动的回调函数

        public IntPtr HookMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode < 0)
            {
                return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
            }
            else
            {
                if (wParam.ToInt32() == WH_MOUSE_Move)
                {
                    Token = 0;
                }
            }
            return IntPtr.Zero; //CallNextHookEx(hHook, nCode, wParam, lParam);
        }

        //摘要
        //    初始化程序时安装消息钩子的默认方法

        public void Start()
        {

            Token = 0;
            //指定委托的具体实现
            _iHookMethod = new HookProc(HookMouseProc);
            //分配句柄
            _iHookProcHandle = GCHandle.Alloc(_iHookMethod);
            using (Process _curProcess = Process.GetCurrentProcess())
            {
                using (ProcessModule _curModule = _curProcess.MainModule)
                {
                    _iHookHandle = SetWindowsHookEx(WH_MOUSE_LL, _iHookMethod, GetModuleHandle(_curModule.ModuleName), 0);
                }
            }
            if (_iHookHandle == IntPtr.Zero)
            {
                throw new Exception("无法安装消息钩子");
            }
            else
            {
                T.Start();
            }

        }

        public void Stop()
        {
            T.Stop();
            if (_iHookHandle != IntPtr.Zero)
            {
                UnhookWindowsHookEx(_iHookHandle);
                _iHookProcHandle.Free();
                _iHookHandle = IntPtr.Zero;
            }
        }
        ~Win32MouseHook()=>Stop();
        public event Action<bool> MouseState;
    }
}
